const {MIME_TYPE_EPUB, UPLOAD_URL,UPLOAD_PATH} = require('../utils/constant')
const fs = require('fs')
const path = require('path')
const Epub = require('../utils/epub')
const xml2js = require('xml2js').parseString

class Book{
    constructor(file,data){
        if(file){
            this.createBookFormFile(file)
        }else{
            this.createBookFormData(data)
        }
    }

    createBookFormFile(file){

        const {
            originalname,
            destination,
            filename,
            mimetype=MIME_TYPE_EPUB,
            path
        } = file
        // console.log('createBookFormFile', file)

        // 电子书的文件后缀
        // const suffix = mimetype===MIME_TYPE_EPUB ?'.epub':''
        const suffix = '.epub'
        // 电子书的原有路径
        const oldBookPath = path
        // 电子书的新路径
        const bookPath = `${destination}/${filename}${suffix}`
        // 电子书的下载URL
        const url=`${UPLOAD_URL}/book/${filename}${suffix}`
        // 电子书解压后的文件路径
        const unzipPath = `${UPLOAD_PATH}/unzip/${filename}`
        // 电子书解压后的文件夹URL
        const unzipUrl = `${UPLOAD_URL}/unzip/${filename}`
        // 创建unzip解压缩文件夹
        if(!fs.existsSync(unzipPath)){
            fs.mkdirSync(unzipPath,{recursive:true})
        }
        // 对电子书进行重命名
        if(fs.existsSync(oldBookPath) && !fs.existsSync(bookPath)){
            fs.renameSync(oldBookPath, bookPath)
        }
        this.fileName = filename // 文件名
        this.path = `/book/${filename}${suffix}` // epub 文件相对路径
        this.filePath = this.path // epub解压缩后相对路径
        this.url = url // epub文件下载链接
        this.title = '' // 书名
        this.author = '' // 作者
        this.publisher = '' // 出版社
        this.contents=[] // 目录
        this.cover = '' //封面url
        this.category = -1 //分类ID
        this.categoryText = '' //分类名称
        this.language = '' // 语种
        this.unzipPath = `unzip/${filename}` // 解压后文件夹相对路径
        this.unzipUrl = unzipUrl // 解压后文件夹链接
        this.originalName = originalname // 电子书文件的原名
    }

    createBookFormData(data){
        this.fileName = data.fileName
        this.cover = data.coverPath
        this.title = data.title
        this.author = data.author
        this.publisher = data.publisher
        this.bookId = data.fileName
        this.language = data.language
        this.rootFile = data.rootFile
        this.originalName = data.originalName
        this.path = data.path || data.filePath
        this.filePath = data.path || data.filePath
        this.unzipPath = data.unzipPath
        this.coverPath = data.coverPath
        this.createUser = data.username
        this.createDt = new Date().getTime()
        this.updateDt = new Date().getTime()
        this.updateType = data.updateType === 0 ? data.updateType : 1
        this.category = data.category || 99
        this.categoryText = data.categoryText || '自定义'
        this.contents = data.contents || []
    }

    getContents(){
        return this.contents;
    }

    parse(){
        return new Promise((resolve,reject)=>{
            const bookPath = `${UPLOAD_PATH}${this.path}`
            const epub = new Epub(bookPath)
            epub.on('error',err =>{
                reject(err)
            })
            epub.on('end',err=>{
                if(err){
                    reject(err)
                }else{
                    const{
                        language,
                        creator,
                        creatorFileAs,
                        title,
                        cover,
                        publisher
                    }=epub.metadata
                    if(!title){
                        reject(new Error('图书标题为空'))
                    }else{
                        this.title = title
                        this.language = language || 'en'
                        this.author = creator || creatorFileAs || 'unknow'
                        this.publisher = publisher || 'unknow'
                        this.rootFile = epub.rootFile
                        try{
                            // 解压电子书
                            this.unzip()
                            // 解压后，在epub对象中 找到toc属性
                            this.parseContents(epub).then(({chapters, chapterTree})=>{
                                this.contents = chapters
                                this.contentsTree = chapterTree
                                // 获取封面
                                const handleGetImage = (err, file, mimeType) =>{
                                    if(err){
                                        reject(err)
                                    }else{
                                        const suffix = mimeType.split('/')[1]
                                        const coverPath = `${UPLOAD_PATH}/img/${this.fileName}.${suffix}`
                                        const coverUrl = `${UPLOAD_URL}/img/${this.fileName}.${suffix}`
                                        fs.writeFileSync(coverPath,file,'binary')
                                        this.coverPath = `/img/${this.fileName}.${suffix}`
                                        this.cover = coverUrl
                                        resolve(this)
                                    }
                                }
                                // 获取封面调用
                                epub.getImage(cover, handleGetImage)
                            })
                        }catch (e) {
                            reject(e)
                        }

                    }
                }
            })

            epub.parse()
        })
    }

    unzip(){
        const AdmZip = require('adm-zip')
        const zip = AdmZip(Book.getPath(this.path))
        zip.extractAllTo(Book.getPath(this.unzipPath), true)
    }

    parseContents(epub){
        function getNcxFilePath() {
            const spine = epub && epub.spine
            const manifest = epub && epub.manifest
            // console.log('spine', spine)
            const ncx = spine.nxc && spine.toc.href
            const id = spine.toc && spine.toc.id
            // 如果ncx文件存在 就返回ncx文件路径
            if(ncx){
                return ncx
            // 如果不存在就返回 manifest的id的href ， 这个是肯定存在的如果不存在，电子书就没目录了，
            // 就没有阅读的价值了
            }else{
                return manifest[id].href
            }
        }

        function findParent(array, level=0, pid='' ){
            return array.map(item=>{
                item.level = level
                item.pid = pid
                if(item.navPoint && item.navPoint.length>0){
                    item.navPoint = findParent(item.navPoint, level+1, item['$'].id)
                // 处理item.navPoint 是对象
                }else if(item.navPoint){
                    item.navPoint.level = level+1
                    item.navPoint.pid = item['$'].id
                }
                return item
            })
        }

        function flatten(array){
            return [].concat(...array.map(item=>{
                if(item.navPoint && item.navPoint.length>0){
                    return [].concat(item,...flatten(item.navPoint))
                } else if (item.navPoint) {
                    return [].concat(item, item.navPoint)
                }  else{
                    return item
                }
            }))
        }

        let ncxFilePath =  getNcxFilePath()
        ncxFilePath = Book.getPath(`${this.unzipPath}/${ncxFilePath}`)
        // console.log(ncxFilePath)
        if(fs.existsSync(ncxFilePath)){
            return new Promise((resolve,reject) => {
                const xml = fs.readFileSync(ncxFilePath, 'utf-8')
                const dir = path.dirname(ncxFilePath).replace(UPLOAD_PATH,'')
                const fileName = this.fileName
                const unzipPath = this.unzipPath
                xml2js(xml,{
                    explicitArray:false,
                    ignoreAttrs:false
                },function (err, json) {
                    if(err){
                        reject(err)
                    }else{
                        const navMap = json.ncx.navMap
                        // console.log('xml',JSON.stringify(navMap))
                        if(navMap.navPoint && navMap.navPoint.length>0){
                            // 对得到的数组进行处理
                            navMap.navPoint = findParent(navMap.navPoint)
                            // 将树状结构 转化为一维结构 拍平
                            const newNavMap = flatten(navMap.navPoint)
                            // 目的是得到一个newNavMap  它和navMap.navPoint没有关系了
                            // console.log(newNavMap === navMap.navPoint) // false 说明我们复制了一个新的navmap不会改动原来的值
                            const chapters = []
                            newNavMap.forEach((chapter, index)=>{
                                const src = chapter.content['$'].src
                                chapter.id = `${src}`
                                chapter.href = `${dir}/${src}`.replace(unzipPath,'')
                                chapter.text = `${UPLOAD_URL}${dir}/${src}`
                                chapter.label = chapter.navLabel.text || ''
                                chapter.navId = chapter['$'].id
                                chapter.fileName = fileName
                                chapter.order = index+1
                                chapters.push(chapter)
                            })
                            const chapterTree = []
                            chapters.forEach(c=>{
                                c.children = []
                                if(c.pid == ''){
                                    chapterTree.push(c)
                                }else{
                                    const parent = chapters.find((_)=>{
                                        return _.navId === c.pid
                                    })
                                    parent.children.push(c)
                                }
                            })
                            resolve({chapters, chapterTree})
                        }else{
                            reject(new Error('目录解析失败，目录数为0'))
                        }

                    }
                })
            })
        }else{
            throw new Error('目录对应的资源文件不存在')
        }
    }

    // 把对象中多余的属性删除，只保留保存在数据库中的数据
    toDb(){
        return {
            fileName: this.fileName,
            cover: this.cover,
            title: this.title,
            author: this.author,
            publisher: this.publisher,
            bookId: this.bookId,
            updateType: this.updateType,
            language: this.language,
            rootFile: this.rootFile,
            originalName: this.originalName,
            filePath: this.path,
            unzipPath: this.unzipPath,
            coverPath: this.coverPath,
            createUser: this.createUser,
            createDt: this.createDt,
            updateDt: this.updateDt,
            category: this.category || 99,
            categoryText: this.categoryText || '自定义'
        }
    }

    reset(){
        if(Book.pathExists(this.filePath)){
            fs.unlinkSync(Book.getPath(this.filePath))
        }
        if(Book.pathExists(this.coverPath)){
            // console.log('Book.getPath(this.coverPath===>',Book.getPath(this.coverPath))
            fs.unlinkSync(Book.getPath(this.coverPath))
        }
        if(Book.pathExists(this.unzipPath)){
            // console.log('Book.getPath(this.unzipPath===>',Book.getPath(this.unzipPath))
            fs.rmdirSync(Book.getPath(this.unzipPath), {recursive:true})
        }
    }

    static pathExists(path){
        if(path.startsWith(UPLOAD_PATH)){
            return fs.existsSync(path)
        }else{
            // 判断传入的path是不是绝对路径，如果不是就根据getpath生成一个绝对路径。
            return fs.existsSync(Book.getPath(path))
        }
    }

    static getPath(path){
        if(!path.startsWith('/')){
            path = `/${path}`
        }
        return `${UPLOAD_PATH}${path}`
    }

    // 编辑图书 获取图书cover
    static getCoverUrl(book){
        // if(+book.updateType === 0){
            const {coverPath} = book
        console.log('coverPath===>',coverPath)
            if(coverPath){
                if(coverPath.startsWith('/')){
                    return `${UPLOAD_URL}${coverPath}`
                }else{
                    return `${UPLOAD_URL}/${coverPath}`
                }
            }else{
                return null
            }
        // }
    }

    // 编辑图书 获取图书目录展示
    static getContentsTree(chapters){
        const chapterTree = []
        chapters.forEach(c=>{
            c.children = []
            if(c.pid == ''){
                chapterTree.push(c)
            }else{
                const parent = chapters.find((_)=>{
                    return _.navId === c.pid
                })
                parent.children.push(c)
            }
        })
        return chapterTree
    }

}

module.exports = Book